package com.dream.oauth2.config;

import com.dream.oauth2.security.CustomOAuth2UserService;
import com.dream.oauth2.security.LoginFailureHandler;
import com.dream.oauth2.security.LoginSuccessHandler;
import com.dream.oauth2.security.QQOAuth2AccessTokenResponseClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.client.RestTemplate;

@Slf4j
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final CustomOAuth2UserService customOAuth2UserService;
    private final ClientRegistrationRepository clientRegistrationRepository;
    private final OAuth2AuthorizedClientRepository authorizedClientRepository;

    // 白名单，直接放行
    private static final String[] WHITE_LIST = {
            "/",
            "/images/**",
            "/login.html",
            "/index.html",
            "/user/current",
            "/oauth2/authorization/github",
            "/oauth2/authorization/gitee",
            "/oauth2/authorization/qq",
            "/login/oauth2/code/github",
            "/login/oauth2/code/gitee",
            "/login/oauth2/code/qq"
    };

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, LoginSuccessHandler loginSuccessHandler,
                                                   LoginFailureHandler loginFailureHandler) throws Exception {
        log.debug("Configuring security filter chain");
        http
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(WHITE_LIST).permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/auth/login.html")
                        .loginProcessingUrl("/perform_login")
                        .successHandler(loginSuccessHandler)
                        .failureHandler(loginFailureHandler)
                        .permitAll()
                )
                .oauth2Login(oauth2 -> oauth2
                        .loginPage("/auth/login.html")
                        .clientRegistrationRepository(clientRegistrationRepository)
                        .authorizedClientRepository(authorizedClientRepository)
                        .userInfoEndpoint(userInfo -> {
                            log.info("配置OAuth2用户信息端点");
                            userInfo.userService(customOAuth2UserService);
                        })
                        .successHandler(loginSuccessHandler)
                        .failureHandler(loginFailureHandler)
                        .tokenEndpoint(token -> token
                                .accessTokenResponseClient(accessTokenResponseClient())
                        )
                )
                .logout(logout -> logout
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/login.html")
                        .permitAll()
                )
                .csrf(csrf -> csrf.disable());

        return http.build();
    }

    @Bean
    public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
        return request -> {
            ClientRegistration clientRegistration = request.getClientRegistration();
            String registrationId = clientRegistration.getRegistrationId();

            if ("qq".equals(registrationId)) {
                return qqAccessTokenResponseClient().getTokenResponse(request);
            } else {
                // 对于GitHub和Gitee使用默认的客户端
                return new DefaultAuthorizationCodeTokenResponseClient().getTokenResponse(request);
            }
        };
    }

    @Bean
    public QQOAuth2AccessTokenResponseClient qqAccessTokenResponseClient() {
        return new QQOAuth2AccessTokenResponseClient(new RestTemplate());
    }
}